import RouteMapManager from './route-map-manager';

/**
 * IMPORTANT!!!
 * Always keep it in mind that permission / authentication / authorization MUST be applied on server side first.
 * Any client side check is for user experience ONLY.
 * NEVER TRUST CLIENT!
 */
export default class RouteMapService {
  /**
   * Extracts role names from request map config attribute.
   * Example: hasRole('admin'), hasAnyRole('reporter', 'planner').
   * Returns string list of role name.
   */
  static extractRoleNames(configAttribute: string): string[] {
    const roleNames: string[] = [];

    const exp = new RegExp(
      `(?:${RouteMapManager.hasRolePrefix}|${RouteMapManager.hasAnyRolePrefix}|${RouteMapManager.hasNoRolePrefix}|${RouteMapManager.hasNoAnyRolePrefix})((.+))`);

    // This would match the role names, like 'admin' or 'reporter', 'planner'.
    const match = exp.exec(configAttribute);

    // If match found.
    if (match) {
      if (match.length >= 2) {
        // Removes all single quotes.
        var matchedRoles = match[1].replaceAll('\'', '');

        // Removes all double quotes.
        matchedRoles = matchedRoles.replaceAll('"', '');

        // Removes all openning parentheses.
        matchedRoles = matchedRoles.replaceAll('(', '');

        // Removes all closing parentheses.
        matchedRoles = matchedRoles.replaceAll(')', '');

        // Splits the string by comma.
        var splitedRoles = matchedRoles.split(',');

        // Trims space for each role name.
        for (const p of splitedRoles) {
          roleNames.push(p.trim());
        }
      }
    }

    return roleNames;
  }

  /**
   * Checks if security request map configAttribute contains any role in roleNames.
   */
  static containsAnyRoleInConfigAttribute(roleNames: string[], configAttribute: string): boolean {
    return this.containsAnyRoleInConfigRoleNames(
      roleNames, this.extractRoleNames(configAttribute));
  }

  /**
   * Checks if configuredRoleNames contains any role in roleNames.
   */
  private static containsAnyRoleInConfigRoleNames(roleNames: string[], configRoleNames: string[]): boolean {
    let containsAnyRole = false;

    for (const roleName of roleNames) {
      for (const configRoleName of configRoleNames) {
        if (roleName.toLowerCase() === configRoleName.toLowerCase()) {
          containsAnyRole = true;
          break;
        }
      }
    }

    return containsAnyRole;
  }
}